#include "stdio.h"
#include "getopt.h"
#include "string.h"
#include "ctype.h"
#include "stdlib.h"

typedef enum
{
	NO_ERROR = 0,
	WRONG_USAGE,
	INVALID_INPUT_RESOLUTION,
	BAD_OP_FILE

} RESULT_CODE;

int isNumber(const int c)
{
	return (c>=48&&c<=57);
}

int stoi(const char *c )
{
    int value = 0;
    while ( isNumber( *c ) )
    {
        value *= 10;
        value += (int) (*c-'0');
        c++;
    }

    return value;
}

int getResolution(const char* strResolution, int* width, int* height)
{
	int result = NO_ERROR;

	int i = 0, j = 0;

	int k = 0;
	char* resolution[2];

	resolution[0] = NULL;
	resolution[1] = NULL;

	while (strResolution[i] != 0)
	{
		if (k > 1)
		{
			fprintf(stderr, "Hubo un error al procesar la resolucion. Especificar solo pixels horizontales y verticales\n");
			return INVALID_INPUT_RESOLUTION;
		}

		j = 0;
		while (strResolution[i] != 0&&strResolution[i] != 'x')
		{
			if (!isNumber(strResolution[i]))
			{
				fprintf(stderr, "Hubo un error al procesar la resolucion: caracteres invalidos.\n");
				return INVALID_INPUT_RESOLUTION;
			}

			resolution[k] = (char*)realloc(resolution[k], j + 2);
			resolution[k][j] = strResolution[i];
			++i;
			++j;
		}

		++i;
		++k;
	}

	//Solo width y height.
	if (k != 2)
	{
		fprintf(stderr, "Hubo un error al procesar la resolucion. Se especifico solo pixels horizontales.\n");
		return INVALID_INPUT_RESOLUTION;
	}

	*width = stoi(resolution[0]);
	*height = stoi(resolution[1]);

	if (resolution[0])
		free(resolution[0]);

	if (resolution[1])
		free(resolution[1]);

	if (*width%8 != 0 || *height%8!= 0)
	{
		fprintf(stderr, "Resolucion invalida.\n");
		return INVALID_INPUT_RESOLUTION;
	}

	return result;
}

int create_pgm_chess(const int width, const int height, const char* outputPath, const int use_stdout)
{
	int result = NO_ERROR;

	FILE* output = NULL;

	if (use_stdout)
		output = stdout;
	else
		output = fopen(outputPath, "w+");

	if (!output)
	{
		fprintf(stderr,"Error al abrir el archivo %s", outputPath);
		return BAD_OP_FILE;
	}

	fprintf(output,"P2\n%d %d\n1\n",width,height);

	if (ferror(output))
	{
		fprintf(stderr,"Error en escritura del archivo %s", outputPath);
		return BAD_OP_FILE;
	}

	unsigned int q_hpixels = width/8;
	unsigned int q_vpixels = height/8;

	int i = 0, h = 0;
	int j = 0, v = 0;

	char* number[2] = {"1", "0"};
	unsigned int x = 0;

	int prev_x = 0;
	while ( v < height)
	{
		x = prev_x;

		for(; j < q_vpixels; j++)
		{
			while (h < width)
			{
				for(; i < q_hpixels; i++)
				{
					fwrite(number[x], sizeof(char), 1, output);

					if (ferror(output))
					{
						fprintf(stderr,"Error en escritura del archivo %s", outputPath);
						return BAD_OP_FILE;
					}

					++h;

					if (h < width)
						fwrite(" ", sizeof(char), 1, output);

					if (ferror(output))
					{
						fprintf(stderr,"Error en escritura del archivo %s", outputPath);
						return BAD_OP_FILE;
					}


				}
				i = 0;
				x = !x;
			}

			h = 0;
			++v;


			//if (v < height)
				fwrite("\n", sizeof(char), 1, output);

			if (ferror(output))
			{
				fprintf(stderr,"Error en escritura del archivo %s", outputPath);
				return BAD_OP_FILE;
			}

			x = prev_x;
		}

		j = 0;
		prev_x = !prev_x;
	}

	if (!use_stdout)
		fclose(output);

	return result;
}

void print_help()
{
	printf("Usage: \n");
	printf("tp0 -h \n tp0 -V \n tp0 [options]\n");
	printf("Options: \n");
	printf("-V, --version \t\tPrint version and quit.\n");
	printf("-h, --help \t\tPrint this information.\n");
	printf("-r, --resolution \tSet bitmap resolution to WxH pixels.\n");
	printf("-o, --output \t\tPath to output file.\n");
}

void print_version()
{
	printf("Version 1.0");
}

int main(int argc, char* argv[])
{
    /*Variables especiales para la funcion getopt_long.*/
    static struct option long_options[] =
    {
    		{"help", no_argument, 0, 'h'},
            {"version", no_argument, 0, 'V'},
            {"resolution", required_argument, 0, 'r'},
            {"output", required_argument, 0, 'o'},
            {0, 0, 0, 0}
    };

    int option_index = 0;

    // Default resolution = 8x8. Default output = stdout.
    int height = 8, width = 8;
    int use_stdout = 1;

    int c;

    int r_flag = 0, o_flag = 0;

    char* resolution = NULL;
    char* outputPath = NULL;

    while ((c = getopt_long (argc, argv, "hVr:o:", long_options, &option_index)) != -1) {
           switch (c) {
            case 'h':
            		print_help();
            		return NO_ERROR;
            case 'V':
                    print_version();
                    return NO_ERROR;
            case 'r':
            		r_flag = 1;
            		// required argument
            		if (optarg != 0)
            		{
            			resolution = malloc(sizeof(char)*(strlen(optarg)+1));
            			strcpy(resolution, optarg);
            		}
                    break;
            case 'o':
            		o_flag = 1;
            		// required argument
            		if (optarg != 0)
            		{
            			outputPath = malloc(sizeof(char)*(strlen(optarg)+1));
            			strcpy(outputPath, optarg);
            		}
            		break;
            case '?':
            		fprintf(stderr,"Error al procesar linea de comandos\n");
                    return WRONG_USAGE;
                    break;
            }
    }


    //Si el programa se ejecuta sin ningún parametro
    if (argc == 1) {
            fprintf(stderr,"Se esperaba argumentos. Ver ayuda con -h.\n");
            return WRONG_USAGE;
    }


    int result = NO_ERROR;

    if (r_flag)
    {
    	result = getResolution(resolution, &width,&height);
    }

    if (result == NO_ERROR && o_flag)
    {
    	//si no es '-'
    	if (strcmp(outputPath, "-"))
    		use_stdout = 0;
    }

    if (result == NO_ERROR)
    	result = create_pgm_chess(width, height, outputPath, use_stdout);

    if (resolution)
    	free(resolution);

    if (outputPath)
    	free(outputPath);


	return result;
}
